package moe.fuqiuluo.api

import com.tencent.crypt.Crypt
import com.tencent.mobileqq.qsec.qsecdandelionsdk.Dandelion
import moe.fuqiuluo.ext.hex2ByteArray
import moe.fuqiuluo.ext.toHexString
import moe.fuqiuluo.utils.EMPTY_BYTE_ARRAY
import moe.fuqiuluo.utils.MD5
import com.shr25.robot.protocol.UnidbgFetchQsign
import java.nio.ByteBuffer

fun customEnergy(uin: Long, salt: ByteArray, data: String): String {
    val session = findSession(uin)

    val sign = session.withLock {
        Dandelion.energy(session.vm, data, salt)
    }
    return sign.toHexString()
}

suspend fun energy(uin: Long, data:String, version: String, phone: String, receipt: String, code: String, guid: String): String {
    UnidbgFetchQsign.logger.debug("Bot(${uin}) custom_energy ${data}")
    val session = findSession(uin)
    if(!(data.startsWith("810_") || data.startsWith("812_"))) {
        throw RuntimeException("data参数不合法")
    }

    val mode = when(data) {
        "810_d", "810_a", "810_f", "810_9" -> "v2"
        "810_2", "810_25", "810_7", "810_24" -> "v1"
        "812_a" -> "v3"
        "812_5" -> "v4"
        else -> ""
    }?.also {
        if (it.isBlank()) throw RuntimeException("无法自动决断mode，请主动提供")
    }

    val salt = when (mode) {
        "v1" -> {
            val salt = ByteBuffer.allocate(8 + 2 + guid.hex2ByteArray().size + 2 + 10)
            salt.putLong(uin)
            salt.putShort(guid.hex2ByteArray().size.toShort())
            salt.put(guid.hex2ByteArray())
            salt.putShort(version.length.toShort())
            salt.put(version.toByteArray())
            salt.array()
        }
        "v2" -> {
            val sub = data.substring(4).toInt(16)
            val salt = ByteBuffer.allocate(4 + 2 + guid.hex2ByteArray().size + 2 + 10 + 4 + 4)
            salt.putInt(0)
            salt.putShort(guid.hex2ByteArray().size.toShort())
            salt.put(guid.hex2ByteArray())
            salt.putShort(version.length.toShort())
            salt.put(version.toByteArray())
            salt.putInt(sub)
            salt.putInt(0)
            salt.array()
        }
        "v3" -> { // 812_a
            val salt = ByteBuffer.allocate(phone.toByteArray().size + 2 + 2 + version.length + 2)
            // 38 36 2D 31 37 33 36 30 32 32 39 31 37 32
            // 00 00
            // 00 06
            // 38 2E 39 2E 33 38
            // 00 00
            // result => 0C051B17347DF3B8EFDE849FC233C88DBEA23F5277099BB313A9CD000000004B744F7A00000000
            salt.put(phone.toByteArray())
            //println(String(phone))
            salt.putShort(0)
            salt.putShort(version.length.toShort())
            salt.put(version.toByteArray())
            salt.putShort(0)
            salt.array()
        }
        "v4" -> { // 812_5
            val key = MD5.toMD5Byte(code)
            val encrypt = Crypt().encrypt(receipt.toByteArray(), key)
            val salt = ByteBuffer.allocate(receipt.toByteArray().size + 2 + encrypt.size)
            salt.put(receipt.toByteArray())
            salt.putShort(encrypt.size.toShort())
            salt.put(encrypt)
            salt.array()
        }
        else -> {
            EMPTY_BYTE_ARRAY
        }
    }

    val sign = session.withLock {
        Dandelion.energy(session.vm, data, salt)
    }
    return sign.toHexString()
}